using Foxel.Models.DataBase;
using Foxel.Services.Storage;
using Foxel.Utils;
using Microsoft.EntityFrameworkCore;
using System.Text.Json;
using Foxel.Services.AI;
using Foxel.Services.VectorDb;


namespace Foxel.Services.Background.Processors
{
    public class VisualRecognitionPayload
    {
        public int PictureId { get; set; }
        public int? UserIdForPicture { get; set; }
    }

    public class VisualRecognitionTaskProcessor(
        IDbContextFactory<MyDbContext> contextFactory,
        IServiceProvider serviceProvider,
        ILogger<VisualRecognitionTaskProcessor> logger,
        IWebHostEnvironment environment)
        : ITaskProcessor
    {
        public async Task ProcessAsync(BackgroundTask backgroundTask)
        {
            if (backgroundTask.Payload == null)
            {
                await UpdateTaskStatusInDb(backgroundTask.Id, TaskExecutionStatus.Failed, 0, "任务 Payload 为空。");
                logger.LogError("视觉识别任务 Payload 为空: TaskId={TaskId}", backgroundTask.Id);
                return;
            }

            VisualRecognitionPayload? payload;
            try
            {
                payload = JsonSerializer.Deserialize<VisualRecognitionPayload>(backgroundTask.Payload);
            }
            catch (JsonException ex)
            {
                logger.LogError(ex, "无法解析视觉识别任务的 Payload: TaskId={TaskId}", backgroundTask.Id);
                await UpdateTaskStatusInDb(backgroundTask.Id, TaskExecutionStatus.Failed, 0, "Payload 解析失败。");
                return;
            }

            if (payload == null || payload.PictureId == 0)
            {
                logger.LogError("视觉识别任务的 Payload 无效或缺少 PictureId: TaskId={TaskId}", backgroundTask.Id);
                await UpdateTaskStatusInDb(backgroundTask.Id, TaskExecutionStatus.Failed, 0,
                    "Payload 无效或缺少 PictureId。");
                return;
            }

            var pictureId = payload.PictureId;
            string thumbnailForAiDownloadPath = string.Empty;
            bool isTempThumbnailFile = false;

            await using var dbContext = await contextFactory.CreateDbContextAsync();
            var currentBackgroundTaskState = await dbContext.BackgroundTasks.FindAsync(backgroundTask.Id);
            if (currentBackgroundTaskState == null)
            {
                logger.LogError("在 VisualRecognitionTaskProcessor 中找不到后台任务: TaskId={TaskId}", backgroundTask.Id);
                return;
            }

            var picture = await dbContext.Pictures
                .Include(p => p.User)
                .ThenInclude(u => u!.Tags) // Ensure Tags on User is loaded if needed
                .Include(p => p.StorageMode) // Include StorageMode
                .Include(p => p.Tags) // Include picture's own tags
                .FirstOrDefaultAsync(p => p.Id == pictureId);

            try
            {
                await UpdateTaskStatusInDb(currentBackgroundTaskState.Id, TaskExecutionStatus.Processing, 10,
                    currentBackgroundTaskState: currentBackgroundTaskState);

                if (picture == null)
                {
                    throw new Exception($"找不到ID为{pictureId}的图片。");
                }

                if (picture.StorageMode == null || picture.StorageModeId < 0)
                {
                    throw new Exception($"图片ID {pictureId} 缺少有效的 StorageMode 配置。");
                }

                if (string.IsNullOrEmpty(picture.ThumbnailPath))
                {
                    // It's possible the thumbnail is generated by PictureTaskProcessor but this task runs before it completes.
                    // Or thumbnail generation failed.
                    logger.LogWarning("图片ID {PictureId} 的缩略图路径为空。AI分析将无法进行或可能失败。", pictureId);
                    // Depending on requirements, you might throw, or try to generate it here, or skip AI.
                    // For now, let's assume it should exist.
                    throw new Exception($"图片ID {pictureId} 的缩略图路径为空，无法进行AI分析。");
                }

                using var scope = serviceProvider.CreateScope();
                var aiService = scope.ServiceProvider.GetRequiredService<AiService>();
                var storageService = scope.ServiceProvider.GetRequiredService<IStorageService>();
                string actualThumbnailPathForAI;

                // Check the StorageType of the associated StorageMode
                if (picture.StorageMode.StorageType == StorageType.Local)
                {
                    logger.LogInformation(
                        "Picture {PictureId} thumbnail is Local. Attempting to download via StorageService for AI.",
                        pictureId);
                    // Fall-through
                }

                // else // Remote storage or consistent handling for Local
                // { 
                await UpdateTaskStatusInDb(currentBackgroundTaskState.Id, TaskExecutionStatus.Processing, 15,
                    currentBackgroundTaskState: currentBackgroundTaskState);
                // Use picture.StorageModeId to download the thumbnail
                thumbnailForAiDownloadPath = await storageService.ExecuteAsync(picture.StorageModeId,
                    provider => provider.DownloadFileAsync(picture.ThumbnailPath));
                actualThumbnailPathForAI = thumbnailForAiDownloadPath;
                isTempThumbnailFile = true;
                // }

                if (string.IsNullOrEmpty(actualThumbnailPathForAI) || !File.Exists(actualThumbnailPathForAI))
                {
                    throw new Exception(
                        $"找不到用于AI分析的缩略图文件: {actualThumbnailPathForAI} (源存储路径: {picture.ThumbnailPath})");
                }

                await UpdateTaskStatusInDb(currentBackgroundTaskState.Id, TaskExecutionStatus.Processing, 20,
                    currentBackgroundTaskState: currentBackgroundTaskState);
                string base64Image = await ImageHelper.ConvertImageToBase64(actualThumbnailPathForAI);

                await UpdateTaskStatusInDb(currentBackgroundTaskState.Id, TaskExecutionStatus.Processing, 40,
                    currentBackgroundTaskState: currentBackgroundTaskState);
                var (title, description) = await aiService.AnalyzeImageAsync(base64Image);

                string finalTitle = !string.IsNullOrWhiteSpace(title) && title != "AI生成的标题"
                    ? title
                    : Path.GetFileNameWithoutExtension(picture.Name); // Fallback to existing name
                string finalDescription = !string.IsNullOrWhiteSpace(description) && description != "AI生成的描述"
                    ? description
                    : picture.Description; // Fallback to existing description
                picture.Name = finalTitle;
                picture.Description = finalDescription;

                await UpdateTaskStatusInDb(currentBackgroundTaskState.Id, TaskExecutionStatus.Processing, 60,
                    currentBackgroundTaskState: currentBackgroundTaskState);
                var combinedText = $"{finalTitle}. {finalDescription}";
                var embedding = await aiService.GetEmbeddingAsync(combinedText);
                picture.Embedding = embedding;

                if (picture.UserId.HasValue && embedding != null && embedding.Length > 0)
                {
                    var vectorDbService = scope.ServiceProvider.GetRequiredService<IVectorDbService>();
                    await vectorDbService.AddPictureToUserCollectionAsync(picture.UserId.Value,
                        new Models.Vector.PictureVector
                        {
                            Id = (ulong)picture.Id, // Ensure Picture.Id can be cast to ulong or adjust type
                            Name = picture.Name,
                            Embedding = embedding
                        });
                }

                await UpdateTaskStatusInDb(currentBackgroundTaskState.Id, TaskExecutionStatus.Processing, 70,
                    currentBackgroundTaskState: currentBackgroundTaskState);
                var availableTagNames = await dbContext.Tags.Select(t => t.Name).ToListAsync();

                await UpdateTaskStatusInDb(currentBackgroundTaskState.Id, TaskExecutionStatus.Processing, 80,
                    currentBackgroundTaskState: currentBackgroundTaskState);
                var matchedTagNames = await aiService.GenerateTagsFromImageAsync(base64Image, availableTagNames, true);

                await UpdateTaskStatusInDb(currentBackgroundTaskState.Id, TaskExecutionStatus.Processing, 90,
                    currentBackgroundTaskState: currentBackgroundTaskState);
                if (matchedTagNames.Any()) // Apply tags even if user is null, if that's desired
                {
                    picture.Tags ??= new List<Tag>();
                    foreach (var tagName in matchedTagNames)
                    {
                        var existingTag =
                            await dbContext.Tags.FirstOrDefaultAsync(t => t.Name.ToLower() == tagName.ToLower());
                        if (existingTag == null)
                        {
                            existingTag = new Tag { Name = tagName.Trim(), Description = tagName.Trim() };
                            dbContext.Tags.Add(existingTag);
                            // await dbContext.SaveChangesAsync(); // Save tag immediately or batch
                        }

                        if (picture.Tags.All(t => t.Id != existingTag.Id)) picture.Tags.Add(existingTag);

                        // Add to user's tags if user exists
                        if (picture.User != null)
                        {
                            picture.User.Tags ??= new List<Tag>();
                            if (picture.User.Tags.All(t => t.Id != existingTag.Id)) picture.User.Tags.Add(existingTag);
                        }
                    }
                }

                await dbContext.SaveChangesAsync();
                await UpdateTaskStatusInDb(currentBackgroundTaskState.Id, TaskExecutionStatus.Completed, 100,
                    completedAt: DateTime.UtcNow, currentBackgroundTaskState: currentBackgroundTaskState);
            }
            catch (Exception ex)
            {
                logger.LogError(ex, "视觉识别任务失败: TaskId={TaskId}, PictureId={PictureId}", currentBackgroundTaskState.Id,
                    pictureId);
                await UpdateTaskStatusInDb(currentBackgroundTaskState.Id, TaskExecutionStatus.Failed,
                    currentBackgroundTaskState.Progress, ex.Message,
                    currentBackgroundTaskState: currentBackgroundTaskState);
            }
            finally
            {
                if (isTempThumbnailFile && File.Exists(thumbnailForAiDownloadPath))
                {
                    try
                    {
                        File.Delete(thumbnailForAiDownloadPath);
                    }
                    catch (Exception ex)
                    {
                        logger.LogWarning(ex, "删除临时AI缩略图文件失败: {FilePath}", thumbnailForAiDownloadPath);
                    }
                }
            }
        }

        // ... (UpdateTaskStatusInDb remains the same) ...
        private async Task UpdateTaskStatusInDb(Guid taskId, TaskExecutionStatus status, int progress,
            string? error = null, DateTime? startedAt = null, DateTime? completedAt = null,
            BackgroundTask? currentBackgroundTaskState = null)
        {
            await using var dbContext = await contextFactory.CreateDbContextAsync();
            var taskToUpdate = currentBackgroundTaskState ?? await dbContext.BackgroundTasks.FindAsync(taskId);

            if (taskToUpdate != null)
            {
                if (currentBackgroundTaskState != null &&
                    dbContext.Entry(currentBackgroundTaskState).State == EntityState.Detached)
                {
                    dbContext.BackgroundTasks.Attach(currentBackgroundTaskState);
                }

                taskToUpdate.Status = status;
                taskToUpdate.Progress = progress;
                taskToUpdate.ErrorMessage =
                    string.IsNullOrEmpty(error)
                        ? taskToUpdate.ErrorMessage
                        : error;
                if (startedAt.HasValue) taskToUpdate.StartedAt = startedAt;
                if (completedAt.HasValue) taskToUpdate.CompletedAt = completedAt;

                if ((status == TaskExecutionStatus.Completed || status == TaskExecutionStatus.Failed) &&
                    !taskToUpdate.StartedAt.HasValue)
                {
                    taskToUpdate.StartedAt = taskToUpdate.CreatedAt;
                }

                if (status == TaskExecutionStatus.Completed || status == TaskExecutionStatus.Failed)
                {
                    taskToUpdate.CompletedAt ??= DateTime.UtcNow;
                }


                await dbContext.SaveChangesAsync();
                logger.LogInformation(
                    "任务状态更新 (VisualRecognitionProcessor): TaskId={TaskId}, Status={Status}, Progress={Progress}%",
                    taskId, status, progress);
            }
            else
            {
                logger.LogWarning("尝试在 VisualRecognitionProcessor 中更新不存在的任务状态: TaskId={TaskId}", taskId);
            }
        }
    }
}